﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Maps.MapControl;
using TrailMap.Projection;
using System.IO;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Threading;

namespace TrailMap.Controls
{
    public partial class Custommap : UserControl
    {
        private Map m_map=null;
        private MainPage m_mainPage = null;
        private CustomMap m_customMap = new CustomMap();
        private MapPolygon m_polygon = null;
        private bool m_flag = false;
        private List<Url> m_allUrls = null;

        public MapPolygon Polygon
        {
            get { return m_polygon; }
        }

        public CustomMap AreaData
        {
            get { return m_customMap; }
            set { m_customMap = value; }
        }
        public Custommap()
        {
            InitializeComponent();
        }

        public void SetMap(Map map, MainPage mainPage)
        {
            this.m_map = map;
            this.m_mainPage = mainPage;
            action = CustomAction.None;

            m_polygon = new MapPolygon();
            m_polygon.Fill = new SolidColorBrush(Colors.Blue);
            m_polygon.Stroke = new SolidColorBrush(Colors.Blue);
            m_polygon.StrokeThickness = 5;
            m_polygon.Opacity = 0.3;
        }

        private CustomAction action;

        public CustomAction Action
        {
            get { return action; }
        }

        private void bttnSelectArea_Click(object sender, RoutedEventArgs e)
        {
            m_map.MousePan -= map_MousePan;
            action = CustomAction.Zoom;
            m_flag = false;
        }

        void map_MousePan(object sender, MapMouseDragEventArgs e)
        {
            e.Handled = true;
        }

        private void bttnSelectZoomLevel_Click(object sender, RoutedEventArgs e)
        {
            this.AreaData.ZoomLevel = m_map.ZoomLevel;
            m_flag = false;
        }
        public string ConvertToFriendlySize(UInt64 fileSize)
        {
            String[] suffixes = { "Bytes", "KB", "MB", "GB", "TB", "PB", "EB" };
            int mult = 0;
            double dFileSize = (double)fileSize;
            while ((dFileSize >= 1024.0) && (mult < suffixes.Length - 1))
            {
                dFileSize /= 1024.0;
                mult++;
            }
            return String.Format("{0} {1}", dFileSize.ToString("0.00"),
            suffixes[mult]);
        }
        private void bttnSaveProjectFile_Click(object sender, RoutedEventArgs e)
        {

            if (m_flag == false)
            {
                MessageBox.Show("please calculate the map size");
            }
            else
            {
                SaveFileDialog dialog;

                dialog = new SaveFileDialog();
                dialog.DefaultExt = ".mapprj";
                dialog.Filter = "Map Project|*.mapprj";

                if (dialog.ShowDialog() == true)
                {

                    using (Stream fs = (Stream)dialog.OpenFile())
                    {
                        XmlSerializer ser = new XmlSerializer(typeof(Url[]));

                        ser.Serialize(fs, m_allUrls.ToArray());

                        //fs.Write(fileBytes, 0, fileBytes.Length);
                        fs.Close();
                        //MessageBox.Show("Save Completed");
                    }
                }

                
                    
            }
        }

        private void bttnDrawArea_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            action = CustomAction.Area;

            m_map.MousePan += map_MousePan;
            m_flag = false;
        }

        private void bttnIsFirstTileAvailable_Click(object sender, RoutedEventArgs e)
        {
            MercatorProjection projections = new MercatorProjection();

            TrailMap.Projection.Point firstPt = projections.GetTile(this.AreaData.StLocation, (int)this.AreaData.ZoomLevel);

            System.Windows.Browser.HtmlPage.PopupWindow(m_mainPage.CurrentSource.GetUri(firstPt.X, firstPt.Y, (int)this.AreaData.ZoomLevel), "FirstTile", new System.Windows.Browser.HtmlPopupWindowOptions());
        }

        private void bttnIsLastTileAvailable_Click(object sender, RoutedEventArgs e)
        {
            MercatorProjection projections = new MercatorProjection();

            TrailMap.Projection.Point lastPt = projections.GetTile(this.AreaData.EtLocation, (int)this.AreaData.ZoomLevel);

            System.Windows.Browser.HtmlPage.PopupWindow(m_mainPage.CurrentSource.GetUri(lastPt.X, lastPt.Y, (int)this.AreaData.ZoomLevel), "LastTile", new System.Windows.Browser.HtmlPopupWindowOptions());
        }

        private void bttnGetMapSize_Click(object sender, RoutedEventArgs e)
        {

            if (MessageBox.Show("do you want to proceed map size calculation.", "Info", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {

                Func<string> worker = () =>
                {

                    m_allUrls = new List<Url>();
                    MercatorProjection projections = new MercatorProjection();
                    List<TrailMap.Projection.Point> allTiles = projections.GetAreaTileList(new LocationRect(this.AreaData.StLocation, this.AreaData.EtLocation), (int)this.AreaData.ZoomLevel, 0);

                    Dispatcher.BeginInvoke(() => m_mainPage.BusyWindow.BusyContent = "Calculating Total number of tiles, please wait...");
                    
                    foreach (TrailMap.Projection.Point item in allTiles)
                    {
                        Url url = new Url();
                        url.Src = m_mainPage.CurrentSource.GetUri(item.X, item.Y, (int)this.AreaData.ZoomLevel).AbsoluteUri;
                        url.Target = string.Format("Img_{0}_{1}_{2}.{3}", item.X, item.Y, (int)this.AreaData.ZoomLevel, m_mainPage.CurrentSource.FileExtn);

                        m_allUrls.Add(url);
                    }

                    return string.Format("Building map completed.\r\nTotal Number of Tiles selected: {0} and approx kmz map size: {1}.", m_allUrls.Count, ConvertToFriendlySize((ulong)(m_allUrls.Count * (24 * 1024))));
                };

                m_mainPage.BusyWindow.BusyContent = "Calculating the Total Number of Tiles";
                m_mainPage.BusyWindow.DisplayAfter = TimeSpan.FromMilliseconds(500);

                m_mainPage.BusyWindow.IsBusy = true;
                ThreadPool.QueueUserWorkItem((state) =>
                {
                    string retVal = worker();
                    Dispatcher.BeginInvoke(() => m_mainPage.BusyWindow.IsBusy = false);
                    Dispatcher.BeginInvoke(() => statusText.Text = retVal);

                    m_flag = true;
                });
            }

        }

        
    }

    public enum CustomAction
    {
        None,
        Area,
        Zoom
    }

    public class Url
    {
        public string Src { get; set; }
        public string Target { get; set; }
    }

    public class CustomMap
    {
        bool flag = false;

        public bool Flag
        {
            get { return flag; }
            set { flag = value; }
        }
        List<string> fileNames;

        public List<string> FileNames
        {
            get { return fileNames; }
            set { fileNames = value; }
        }
        double zoomLevel;

        public double ZoomLevel
        {
            get { return zoomLevel; }
            set { zoomLevel = value; }
        }
        Location etLocation;

        public Location EtLocation
        {
            get { return etLocation; }
            set { etLocation = value; }
        }
        Location stLocation;

        public Location StLocation
        {
            get { return stLocation; }
            set { stLocation = value; }
        }
    }
}
